package poker;
import java.util.Scanner;
import java.util.Random;

public class Table{
    int numberOfCurrentPlayer,actionsPerformed=0,highestBid=0,numberOfAllIns=0;
    int playersBetsThisTurn[]=new int[] {0,0,0,0};
	int betValue;
	int numberOfAction;
  static Deck deck =new Deck();
  private int input;
  int numberOfPlayers;
public int numberOfHumanPlayers;
 int numberOfChips;
 int entryFee;
 int tablePool;
 int numberOfActivePlayers;
 int betPosition;
  boolean enoughPlayers,playedAllIn;
  Player players[]=new Player[4];
  Hand hands[]=new Hand[4];
  int playersChips[]=new int[4];
  int playersWins[]=new int[4];
  int playersBets[]=new int[4];
  int playersActivity[]=new int[4];
  Random generator=new Random();

  /** RESETOWANIE WSZYSTKICH USTAWIEN. */
  private void resetAllSettings(){
    numberOfPlayers=0; numberOfHumanPlayers=0; numberOfChips=0; entryFee=0; tablePool=0; numberOfActivePlayers=0; betPosition=generator.nextInt(5); enoughPlayers=false; playedAllIn=false;
	for(int i=0;i<4;i++){players[i]=null; hands[i]=null; playersChips[i]=0; playersWins[i]=0; playersBets[i]=0; playersActivity[i]=0;}
  }

  /** WCZYTYWANIE LICZBY GRACZY. */
  private void loadNumberOfPlayers(){
    Scanner keyboard=new Scanner(System.in);
	try{
      do{System.out.print("Number of players (2-4): "); input=keyboard.nextInt();} while((input<2)||(input>4));
	} catch (Exception e){System.out.println("INVALID INPUT"); System.exit(0);} /** DLA NIEPOPRAWNEJ WARTOSCI PRZERYWAMY DZIALANIE. */
	numberOfPlayers=input;
  }

  /** WCZYTYWANIE LICZBY GRACZY-LUDZI. */
  private void loadNumberOfHumanPlayers(){
    Scanner keyboard=new Scanner(System.in);
	try{
      do{System.out.print("Number of human players (0-" + numberOfPlayers + "): "); input=keyboard.nextInt();} while((input<0)||(input>numberOfPlayers));
	} catch (Exception e){System.out.println("INVALID INPUT"); System.exit(0);} /** DLA NIEPOPRAWNEJ WARTOSCI PRZERYWAMY DZIALANIE. */
	numberOfHumanPlayers=input;
  }

  /** UTWORZENIE GRACZY. */
   private void createPlayers(){
    Scanner keyboard=new Scanner(System.in);
	String humanName;
    for(int i=0;i<4;i++){players[i]=null;}
    for(int i=0;i<numberOfHumanPlayers;i++){
	  humanName="Human" + (i+1);
	  try{System.out.print("[Human" + (i+1) + "] Choose your name: "); humanName=keyboard.next();
	  } catch (Exception e){System.out.println("INVALID INPUT"); System.exit(0);} /** DLA NIEPOPRAWNEJ WARTOSCI PRZERYWAMY DZIALANIE. */
	  players[i]=new Human(humanName);
	  playersActivity[i]=1;}
	for(int i=0;i<(numberOfPlayers-numberOfHumanPlayers);i++){
	  players[numberOfHumanPlayers+i]=new Bot("Bot" + (i+1));
	  playersActivity[numberOfHumanPlayers+i]=1;
    }
  }
   

  /** WCZYTYWANIE ILOSCI ZETONOW I WYSOKOSCI WPISOWEGO. */
  private void loadChipsSettings(){
    Scanner keyboard=new Scanner(System.in);
	try{
      do{System.out.print("Number of chips (2-999): "); input=keyboard.nextInt();} while((input<2)||(input>999));
	} catch (Exception e){System.out.println("INVALID INPUT"); System.exit(0);} /** DLA NIEPOPRAWNEJ WARTOSCI PRZERYWAMY DZIALANIE. */
	numberOfChips=input;
	for(int i=0;i<numberOfPlayers;i++){playersChips[i]=numberOfChips;}
	try{
      do{System.out.print("Entry fee (1-" + (numberOfChips-1) + "): "); input=keyboard.nextInt();} while((input<1)||(input>(numberOfChips-1)));
	} catch (Exception e){System.out.println("INVALID INPUT"); System.exit(0);} /** DLA NIEPOPRAWNEJ WARTOSCI PRZERYWAMY DZIALANIE. */
	entryFee=input;
  }

  /** WYRZUCANIE GRACZY BEZ ZETONOW, SPRAWDZANIE LICZBY POZOSTALYCH GRACZY. */
  /** KONTROLA KOLEJKI DO NASTEPNEJ LICYTACJI, RESETOWANIE ZMIENNEJ playedAllIn. */
  void checkPlayers(){
    numberOfActivePlayers=0;
	for(int i=0;i<numberOfPlayers;i++){playersActivity[i]=1;}
    for(int i=0;i<numberOfPlayers;i++){if((playersChips[i]-1)<entryFee){playersActivity[i]=0;}}
	for(int i=0;i<numberOfPlayers;i++){if(playersActivity[i]==1){numberOfActivePlayers+=1;}}
	if(numberOfActivePlayers<2){enoughPlayers=false;}
	else{enoughPlayers=true;}
    if(betPosition<3){betPosition++;}
	else{betPosition=0;}
	playedAllIn=false;
	 System.out.println("Sprawdzilem "+numberOfPlayers+" graczy. Mozliwosc gry:"+enoughPlayers );
  }

  /** TURA WPISOWEGO. */
  void entryFeeTurn(){
	for(int i=0;i<numberOfPlayers;i++){
	  if(playersActivity[i]==1){playersBets[i]+=entryFee; tablePool+=entryFee; playersChips[i]-=entryFee;}
	}
	System.out.println("entryTurn" );
  }

  /** UTWORZENIE RAK GRACZY. */
   void createHands(){
    for(int i=0;i<4;i++){hands[i]=null;}
    for(int i=0;i<numberOfPlayers;i++){if(playersActivity[i]==1) hands[i]=new Hand(deck);}
    System.out.println("create Hands" );
   }

  /** TURA WYSWIETLANIA KART GRACZY. */
  void displayTurn(){
	for(int i=0;i<numberOfPlayers;i++){
	  if(playersActivity[i]==1){
	    System.out.println(players[i].getName());
	    hands[i].display();
	    System.out.println();
      }
	}
  }

  /** TURA WYMIANY KART PRZEZ GRACZY. */
  void exchangeTurn(){
    for(int i=0;i<numberOfPlayers;i++){
	  if(playersActivity[i]==1) hands[i].exchange(deck,players[i].exchangeCards());
	}
  }

  /** TURA WYSWIETLANIA WYNIKOW GRACZY. */
  void evaluateTurn(){
    for(int i=0;i<numberOfPlayers;i++){
	  if(playersActivity[i]==1){
	    System.out.print(players[i].getName() + " ");
	    //hands[i].evaluate();
	    System.out.println("\n");
	  }
	}
  }

  /** TURA WYBIERANIA ZWYCIEZCY I ODDAWANIA MU STAWKI. */
  void winnerTurn(){
    int winner=(-1),draw=0;
    for(int i=0;i<numberOfPlayers;i++){
	  if(playersActivity[i]==1){
	    if(winner==(-1)){winner=i;}
        else if(hands[i].compareTo(hands[winner])==0){draw=1;}
        else if(hands[i].compareTo(hands[winner])==1){draw=0; winner=i;}
	  }
	}
	if(winner==(-1)){draw=1;}
	if(draw==1){System.out.println("Draw!");}
	else{
      for(int i=0;i<numberOfPlayers;i++){
	    if(winner!=i){
	      if(playersBets[i]>playersBets[winner]){playersChips[winner]+=playersBets[winner]; playersBets[i]-=playersBets[winner];}
	      else{playersChips[winner]+=playersBets[i]; playersBets[i]=0;}
	    }
	  }
	  playersChips[winner]+=playersBets[winner]; playersBets[winner]=0;
	  for(int i=0;i<numberOfPlayers;i++){ /** ODDAJEMY GRACZOM "NADMIAR" Z ICH STAWEK (JESLI GRALI DO KONCA). */
	    if(playersActivity[i]==1){playersChips[i]+=playersBets[i]; playersBets[i]=0;}
	  }
	  playersWins[winner]+=1;
	  System.out.println(players[winner].getName() + " wins!\n");
	}
	tablePool=0;
  }

  /** TURA WYSWIETLANIA RANKINGU. */
  void displayRanking(){
    for(int i=0;i<numberOfPlayers;i++){
	  System.out.println(players[i].getName());
	  System.out.println("Wins: " + playersWins[i]);
      System.out.println("Chips: " + playersChips[i]);
	  System.out.println();
      }
	}

  /** TURA LICYTACJI. */
  /** NUMERY AKCJI: 1-Check, 2-Bet, 3-Raise, 4-Call, 5-Fold, 6-All-In. */
  void betTurn(){
    int betValue,numberOfCurrentPlayer,numberOfAction,actionsPerformed=0,highestBid=0,numberOfAllIns=0;
    int playersBetsThisTurn[]=new int[] {0,0,0,0};
	numberOfCurrentPlayer=betPosition;
	while((actionsPerformed<(numberOfActivePlayers))&&(numberOfActivePlayers>1)){
	  numberOfAction=0;
	  if(playersActivity[numberOfCurrentPlayer]==1){
	    if(highestBid==0){numberOfAction=players[numberOfCurrentPlayer].betAction(true,false,true,true);}
		else if((highestBid!=0)&&(numberOfAllIns==0)&&(playersChips[numberOfCurrentPlayer]>(highestBid-playersBetsThisTurn[numberOfCurrentPlayer]))&&(playersChips[numberOfCurrentPlayer]>(highestBid-(playersBets[numberOfCurrentPlayer]-entryFee)+1))){numberOfAction=players[numberOfCurrentPlayer].betAction(false,false,true,true);}
		else if((highestBid!=0)&&(numberOfAllIns==0)&&(playersChips[numberOfCurrentPlayer]>(highestBid-playersBetsThisTurn[numberOfCurrentPlayer]))&&(!(playersChips[numberOfCurrentPlayer]>(highestBid-(playersBets[numberOfCurrentPlayer]-entryFee)+1)))){numberOfAction=players[numberOfCurrentPlayer].betAction(false,false,true,false);}
		else if((highestBid!=0)&&(numberOfAllIns==0)&&(!(playersChips[numberOfCurrentPlayer]>(highestBid-playersBetsThisTurn[numberOfCurrentPlayer])))){numberOfAction=players[numberOfCurrentPlayer].betAction(false,false,false,false);}
		else if((playersChips[numberOfCurrentPlayer]>highestBid)&&(playersChips[numberOfCurrentPlayer]>(highestBid+1))){numberOfAction=players[numberOfCurrentPlayer].betAction(false,true,true,true);}
		else if((playersChips[numberOfCurrentPlayer]>highestBid)&&(!(playersChips[numberOfCurrentPlayer]>(highestBid+1)))){numberOfAction=players[numberOfCurrentPlayer].betAction(false,true,true,false);}
		else if(!(playersChips[numberOfCurrentPlayer]>highestBid)){numberOfAction=players[numberOfCurrentPlayer].betAction(false,true,false,false);}
	    switch(numberOfAction){
	      case 1:
		    System.out.println(players[numberOfCurrentPlayer].getName() + " plays CHECK");
		    break;
          case 2:
		    betValue=players[numberOfCurrentPlayer].getValue(1,(playersChips[numberOfCurrentPlayer]-1));
		    System.out.println(players[numberOfCurrentPlayer].getName() + " plays BET (" + betValue + ")");
		    tablePool+=betValue;
		    playersChips[numberOfCurrentPlayer]-=betValue;
		    playersBetsThisTurn[numberOfCurrentPlayer]+=betValue;
		    if(betValue>highestBid){highestBid=betValue;}
		    actionsPerformed++;
		    break;
	      case 3:
		    betValue=players[numberOfCurrentPlayer].getValue((highestBid+1),(playersChips[numberOfCurrentPlayer]-1));
		    System.out.println(players[numberOfCurrentPlayer].getName() + " plays RAISE (" + betValue + ")");
		    tablePool+=(betValue-playersBetsThisTurn[numberOfCurrentPlayer]);
		    playersChips[numberOfCurrentPlayer]-=(betValue-playersBetsThisTurn[numberOfCurrentPlayer]);
            playersBetsThisTurn[numberOfCurrentPlayer]+=(betValue-playersBetsThisTurn[numberOfCurrentPlayer]);
		    highestBid=betValue;
		    actionsPerformed=1;
		    break;
	      case 4:
		    betValue=highestBid;
		    System.out.println(players[numberOfCurrentPlayer].getName() + " plays CALL (" + betValue + ")");
            tablePool+=(betValue-playersBetsThisTurn[numberOfCurrentPlayer]);
		    playersChips[numberOfCurrentPlayer]-=(betValue-playersBetsThisTurn[numberOfCurrentPlayer]);
		    playersBetsThisTurn[numberOfCurrentPlayer]+=(betValue-playersBetsThisTurn[numberOfCurrentPlayer]);
		    actionsPerformed++;
		    break;
	      case 5:
		    System.out.println(players[numberOfCurrentPlayer].getName() + " plays FOLD");
		    playersActivity[numberOfCurrentPlayer]=0;
		    numberOfActivePlayers--;
		    break;
	      case 6:
		    betValue=playersChips[numberOfCurrentPlayer];
		    System.out.println(players[numberOfCurrentPlayer].getName() + " plays ALL-IN (" + (betValue+playersBetsThisTurn[numberOfCurrentPlayer]) + ")");
		    tablePool+=betValue;
		    playersChips[numberOfCurrentPlayer]-=betValue;
		    playersBetsThisTurn[numberOfCurrentPlayer]+=betValue;
		    if(betValue>highestBid){highestBid=betValue;}
		    if(numberOfAllIns==0) actionsPerformed=0;
			playedAllIn=true;
		    numberOfAllIns++;
		    actionsPerformed++;
		    break;
        }
		System.out.println();
      }
      if(numberOfCurrentPlayer<3){numberOfCurrentPlayer++;}
	  else{numberOfCurrentPlayer=0;}
    }
	for(int i=0;i<numberOfPlayers;i++){playersBets[i]+=playersBetsThisTurn[i];}
  }

  /** KONSTRUKTOR KLASY. */
  Table(){
	
	System.out.println("---------------------------------------------------------");
	System.out.println("GAME SETTINGS");
	System.out.println("---------------------------------------------------------\n");
    resetAllSettings();
    loadNumberOfPlayers();
	loadNumberOfHumanPlayers();
	createPlayers();
	System.out.println("[TABLE] PUNKT KONTROLNY [-2] NumberOf Players = " + numberOfPlayers);
	loadChipsSettings();
	checkPlayers();
	System.out.println("[TABLE] PUNKT KONTROLNY [-2]");
	System.out.println();
	while(enoughPlayers){
		  System.out.println("[TABLE] PUNKT KONTROLNY [0]" );
	      entryFeeTurn();	System.out.println("[TABLE] PUNKT KONTROLNY [1]" );

		  createHands();System.out.println("[TABLE] PUNKT KONTROLNY [2]" );
		  System.out.println("---------------------------------------------------------");
		  System.out.println("DISPLAY TURN");
		  System.out.println("---------------------------------------------------------\n");
	      displayTurn();
		  System.out.println("---------------------------------------------------------");
		  System.out.println("FIRST BET TURN");
		  System.out.println("---------------------------------------------------------\n");
	      betTurn();
		  if(numberOfActivePlayers>1){
		    System.out.println("---------------------------------------------------------");
		    System.out.println("EXCHANGE TURN");
		    System.out.println("---------------------------------------------------------\n");
		    exchangeTurn();
		    System.out.println("---------------------------------------------------------");
		    System.out.println("DISPLAY TURN");
		    System.out.println("---------------------------------------------------------\n");
	        displayTurn();
			if(!playedAllIn){
		      System.out.println("---------------------------------------------------------");
		      System.out.println("SECOND BET TURN");
		      System.out.println("---------------------------------------------------------\n");
	          betTurn();
			}
	        if(numberOfActivePlayers>1){
	          System.out.println("---------------------------------------------------------");
		      System.out.println("EVALUATE TURN");
		      System.out.println("---------------------------------------------------------\n");
		      evaluateTurn();
			}
	      }
	      System.out.println("---------------------------------------------------------");
	      System.out.println("WINNER TURN");
	      System.out.println("---------------------------------------------------------\n");
	      winnerTurn();
	      System.out.println("---------------------------------------------------------");
		  System.out.println("DISPLAY RANKING");
		  System.out.println("---------------------------------------------------------\n");
		  displayRanking();
		  checkPlayers();
		}
	
  }

}